package vn.vfriends.id.bean;

import java.io.Serializable;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.enterprise.context.Conversation;
import javax.enterprise.context.ConversationScoped;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;
import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import vn.vfriends.id.jpa.controller.exceptions.ViolationException;
import vn.vfriends.id.jpa.entity.Group;
import vn.vfriends.id.jpa.entity.User;
import vn.vfriends.id.service.GroupService;
import vn.vfriends.id.service.UserService;
import vn.vfriends.id.util.StringUtil;

/**
 *
 * @author tuan@vfriends.vn
 */
@Named
@ConversationScoped
public class RegisterBean implements Serializable {

    private static final Logger logger = LoggerFactory.getLogger(RegisterBean.class);
    
    private String username;
    
    private String email;
    
    private String password;
    
    private String reTypePassword;
    
    private String fullName;
    
    @Inject private UserService userService;
    
    @Inject private GroupService groupService;
    
    @Inject private Conversation conversation;
    
    @Resource(lookup = "mail/noreply")
    private Session mailSession;

    @PostConstruct
    public void init() {
        if (conversation.isTransient()) {
            conversation.begin();
        }
    }

    public Conversation getConversation() {
        return conversation;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }
    
    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getReTypePassword() {
        return reTypePassword;
    }

    public void setReTypePassword(String reTypePassword) {
        this.reTypePassword = reTypePassword;
    }

    public String getFullName() {
        return fullName;
    }

    public void setFullName(String fullName) {
        this.fullName = fullName;
    }
    
    public void registerAction() {
        try {
            FacesContext context = FacesContext.getCurrentInstance();
            if(!this.password.equals(this.reTypePassword)) {
                context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Re-type password is not match", ""));
                return;
            } else {
                //  Check username
                User user = this.userService.findByUsername(username);
                if(user != null) {
                    FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Username is used", ""));
                    return;
                }
                user = this.userService.findByEmail(email);
                if(user != null) {
                    FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Email is used", ""));
                    return;
                }
                
                user = new User();
                user.setUsername(this.username);
                user.setEmail(this.email);
                user.setFullName(this.fullName);
                user.setPassword(DigestUtils.md5Hex(this.password));
                user.setActivated(false);
                user.setExternal(false);
                String verificationKey = Base64.encodeBase64String(DigestUtils.sha256(email + "-" + this.password));
                user.setVerificationKey(verificationKey);
                
                Group group = this.groupService.findByCode(Group.GroupCode.CUSTOMER);
                if(group != null) {
                    List<Group> groupList = new ArrayList<Group>();
                    groupList.add(group);
                    user.setGroups(groupList);
                }
                
                userService.create(user);
                
                //  Send verification key to the email
                HttpServletRequest request = (HttpServletRequest)context.getExternalContext().getRequest();
                String subject = "Please Verify Your Email Address";
                String body = "Please click the link below to verify your email address.\n";
                body += request.getRequestURL().substring(0, request.getRequestURL().length() - request.getRequestURI().length()).toString();
                body += request.getContextPath() + "/verification.jsf?key=" + URLEncoder.encode(verificationKey, "UTF-8");
                
                this.sendEmail(email, subject, body);
            }
            FacesContext.getCurrentInstance().getExternalContext().redirect("success.jsf");
        } catch (Exception ex) {
            logger.error(ex.getMessage(), ex);
            if(ex instanceof ViolationException) {
                List<String> messages = ((ViolationException)ex).getMessages();
                for(String mess : messages) {
                    if(!StringUtil.isEmpty(mess))
                        FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, mess, ""));
                }
            } else {
                FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, ex.getMessage(), ""));
            }
        }
    }
    
    private void sendEmail(String to, String subject, String body) throws Exception {
        MimeMessage message = new MimeMessage(mailSession);
        message.setFrom(new InternetAddress(mailSession.getProperty("mail.from")));
        InternetAddress[] address = {new InternetAddress(to)};
        message.setRecipients(Message.RecipientType.TO, address);
        message.setSubject(subject);
        message.setSentDate(new Date());
        message.setText(body);
        Transport.send(message);
    }
}
